package com.starbaba.system.attach.view;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.starbaba.core.service.CommonService;
import com.starbaba.core.utils.SpringContextManager;
import com.starbaba.core.utils.config.ConfigFileFactory;
import com.starbaba.core.utils.io.IOUtilFactory;
import com.starbaba.core.web.constant.WebConstants;
import com.starbaba.system.attach.model.AttachVO;
import com.starbaba.system.user.model.UserVO;
import com.tuanzi.server.loan_base.util.DateFormatFactory;


/**
 * 上传控件，分为2段式提交：
 * <br>1. 客户端的文件 --> 服务端临时目录文件
 * <br>2. 服务端临时目录文件 --> FastDFS目录
 *
 * @Copyright: Copyright (c) 2006
 * @Company: Revenco Tech Ltd.
 * @anthor chenminhui<chenminhui@revenco.com>
 * @since 2014-11-4 上午10:27:12
 * @version V1.0
 */
@SuppressWarnings("all")
public class UploadServlet extends HttpServlet {
	
	static final Logger logger = Logger.getLogger(UploadServlet.class);

	public static final String FILE_UPLOAD_PROGRESS = "FILE_UPLOAD_PROGRESS";
	private static final int HTTP_REDUNDANT_LENGTH = 1024; // 1KB
	public static final String FILE_UPLOAD_TEMPDIR = "/upload";
	
	
	private CommonService service;
	
	public UploadServlet(){
		service = SpringContextManager.getBean("commonServiceImpl");
	}

	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		UploadProgress progress = new UploadProgress();
		HttpSession session = request.getSession();
		UserVO userVO = (UserVO) session.getAttribute(WebConstants.SESSION_ATTRIBUTE_USER);
//		UserVO userVO = (UserVO) SessionManager.getSession(request, response).getAttribute(WebConstants.SESSION_ATTRIBUTE_USER);
		session.setAttribute(FILE_UPLOAD_PROGRESS, progress);
		try{
			this.uploadFile(request, response, progress, userVO);
		}catch(Exception ex) {
			progress.setStatus(UploadProgress.STATUS_ERROR);
			logger.error(ex, ex);
		}
		progress.setStatus(UploadProgress.STATUS_DONE);
	}
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}
	
	public ServletFileUpload initFileUpload(HttpServletRequest request) {
		DiskFileItemFactory factory=new DiskFileItemFactory();
		
		/**
		 * 获取临时保存目录
		 */
		String path = request.getSession().getServletContext().getRealPath(FILE_UPLOAD_TEMPDIR);
	       
        factory.setRepository(new File(path));
        
        /**
         * 设置最多只允许在内存中存储的数据，单位：字节
         * 当不超过1M时直接先存储在内存中，再进行内存对硬盘的IO
         * 当超过时候先存储在临时目录path当中
         */
        factory.setSizeThreshold(1024*1024);
        
        ServletFileUpload upload = new ServletFileUpload(factory);
        
        String maxSize = request.getParameter("maxSize");
		if(StringUtils.isNotBlank(maxSize) && StringUtils.isNumeric(maxSize)) {
			/**
			 * 设置允许用户上传文件大小，单位：字节
			 */
			upload.setFileSizeMax(Long.valueOf(maxSize));
		}
		
        return upload;
	}
	
	/**
	 * 上传文件操作
	 * @param request
	 * @param response
	 * @param progress
	 * @param userVO
	 */
	public void uploadFile(HttpServletRequest request, HttpServletResponse response, UploadProgress progress, UserVO userVO){
        int totalSize = request.getContentLength() - HTTP_REDUNDANT_LENGTH;
        progress.setTotalSize(totalSize);
        
        String tempUploadPath = ConfigFileFactory.getInstance().get("application").getValue("env.upload.path");
        String savePath = FileUtils.getTempDirectoryPath() + IOUtilFactory.SYSTEM_FILE_SEPARATOR + tempUploadPath;
        logger.info("上传临时目录：" + savePath);
        
        OutputStream os = null;
        try {
        	ServletFileUpload upload = initFileUpload(request);
            
        	IOUtilFactory.mkdir(savePath);
            
			List<FileItem> fileItemList = upload.parseRequest(request);
			for(FileItem fileItem : fileItemList){
				if(!fileItem.isFormField()){
					
					String fullFileName = fileItem.getName();
					String fileName = fullFileName.substring(fullFileName.lastIndexOf("\\") + 1).toString();
					if(StringUtils.isNotBlank(fileName)){
						String newFileName = userVO.getUserid() + "_"
							+ DateFormatFactory.getInstance("yyyyMMddHHmmss").format(new java.util.Date()) + "_"
							+ fileName;
						String month = DateFormatFactory.getInstance("yyyyMM").format(new java.util.Date());
						String newSavePath = savePath + IOUtilFactory.SYSTEM_FILE_SEPARATOR + month;
						/*
						File dir = new File(newSavePath);
						if(!dir.exists()){
							dir.mkdir();
						}
						File targetFile = new File(newSavePath + separator + newFileName);
						this.copy(fileItem, targetFile, progress);
						*/
						
						//1. 本地文件上传到服务端临时目录
						os = IOUtilFactory.openOutputStream(newSavePath, newFileName);
						copy(fileItem, os, progress);
						
						//2. 服务端临时文件上传到FastDFS
//						List<NameValuePair> nvpList = new ArrayList<NameValuePair>();
//						nvpList.add(new NameValuePair("filename", fileItem.getName()));
//						nvpList.add(new NameValuePair("filesize", String.valueOf(fileItem.getSize())));
//						nvpList.add(new NameValuePair("contenttype", fileItem.getContentType()));
						
						File localFile = new File(newSavePath, newFileName);
//						FdfsManager.uploadFile(localFile, nvpList.toArray(new NameValuePair[0]));
						
						//3. 删除服务端临时文件
						FileUtils.forceDelete(localFile);
						
						//4. 记录到库表【附件表】
						AttachVO attachVO = this.saveAttachVO(fileItem.getName(), savePath, month, newFileName, fileItem.getContentType(), userVO);
						progress.setAttachVO(attachVO);
						progress.setAttachId(attachVO.getAttid().toString());
					}
				}
			}
		} catch (FileUploadException e) {
			progress.setErrorMsg(e.getMessage());
			progress.setStatus(UploadProgress.STATUS_ERROR);
			logger.error(e, e);
		} catch (Exception ex){
			progress.setErrorMsg(ex.getMessage());
			progress.setStatus(UploadProgress.STATUS_ERROR);
			logger.error(ex, ex);
		} finally {
			if(os != null)	IOUtils.closeQuietly(os);
		}
		progress.setStatus(UploadProgress.STATUS_DONE);
	}
	
	/**
	 * 保存文件
	 * @param fileItem
	 * @param targetFile
	 * @param progress
	 * @throws IOException 
	 */
	public void copy(FileItem fileItem, File targetFile, UploadProgress progress) throws IOException{
		OutputStream os = FileUtils.openOutputStream(targetFile);
		try {
			copy(fileItem, os, progress);
		} finally {
			IOUtils.closeQuietly(os);
		}
		
    }
	
	/**
	 * 保存文件
	 * @param fileItem
	 * @param os
	 * @param progress
	 */
	public void copy(FileItem fileItem, OutputStream os, UploadProgress progress) {
		if(os == null)	return;
		
		InputStream inStream = null;
    	try{
    		inStream = fileItem.getInputStream();
    		
    		int br = 0;
			int fileLength = 0;
			byte[] buffer = new byte[1024];
			long bytesRead = 0L;
			
			while((br = inStream.read(buffer)) != -1){
				os.write(buffer, 0, br);
				bytesRead = bytesRead + br;
				fileLength += br;
				progress.setBytesRead(bytesRead);
			}
    	} catch(Exception ex){
    		logger.error(ex, ex);
    	} finally {
    		IOUtils.closeQuietly(inStream);
    	}
	}
	
	/**
	 * 保存附件对象
	 * @param fileName
	 * @param savePath
	 * @param saveName
	 * @param user
	 * @return
	 * @throws Exception
	 */
	public AttachVO saveAttachVO(String fileName, String savePath, String saveMonth, String saveName, String contentType, UserVO user) throws Exception{
		AttachVO attachVO = new AttachVO();
		attachVO.setFilename(fileName);
		attachVO.setSavepath(savePath);
		attachVO.setSavemonth(saveMonth);
		attachVO.setUploadtime(new java.util.Date());
		attachVO.setUserid(user.getUserid());
		attachVO.setContenttype(contentType);
		
		return (AttachVO) this.getService().doCreate(AttachVO.class, attachVO);
	}

	public CommonService getService() {
		return service;
	}
	public void setService(CommonService service) {
		this.service = service;
	}

}
